package com.xjx.programmer.service;

import com.xjx.programmer.model.DatabaseConnection;
import com.xjx.programmer.model.ExecuteResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Redis 数据库服务
 */
@Slf4j
@Service
public class RedisService {

    /**
     * 创建 Redis 连接
     */
    public RedisTemplate<String, Object> createRedisTemplate(DatabaseConnection connection) {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(connection.getHost());
        config.setPort(connection.getPort());
        config.setDatabase(connection.getDatabaseName() != null ? Integer.valueOf(connection.getDatabaseName()) : 0);
        
        if (connection.getPassword() != null && !connection.getPassword().isEmpty()) {
            config.setPassword(connection.getPassword());
        }
        
        JedisConnectionFactory connectionFactory = new JedisConnectionFactory(config);
        connectionFactory.afterPropertiesSet();
        
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 设置序列化器
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        template.afterPropertiesSet();
        return template;
    }

    /**
     * 测试 Redis 连接
     */
    public boolean testConnection(DatabaseConnection connection) {
        try {
            RedisTemplate<String, Object> redisTemplate = createRedisTemplate(connection);
            redisTemplate.opsForValue().set("test_connection", "test", 5, TimeUnit.SECONDS);
            String value = (String) redisTemplate.opsForValue().get("test_connection");
            return "test".equals(value);
        } catch (Exception e) {
            log.error("测试 Redis 连接失败", e);
            return false;
        }
    }

    /**
     * 执行 Redis 命令
     */
    public ExecuteResult executeCommand(DatabaseConnection connection, String command) {
        RedisTemplate<String, Object> redisTemplate = createRedisTemplate(connection);
        return executeCommand(redisTemplate, command);
    }

    /**
     * 执行 Redis 命令（内部方法）
     */
    private ExecuteResult executeCommand(RedisTemplate<String, Object> redisTemplate, String command) {
        long startTime = System.currentTimeMillis();
        
        try {
            String[] parts = command.trim().split("\\s+");
            if (parts.length == 0) {
                return ExecuteResult.builder()
                        .success(false)
                        .message("命令不能为空")
                        .executeTime(System.currentTimeMillis() - startTime)
                        .errorMessage("命令格式错误")
                        .build();
            }
            
            String cmd = parts[0].toLowerCase();
            List<Map<String, Object>> data = new ArrayList<>();
            
            switch (cmd) {
                case "get":
                    return executeGet(redisTemplate, parts, startTime);
                case "set":
                    return executeSet(redisTemplate, parts, startTime);
                case "del":
                    return executeDel(redisTemplate, parts, startTime);
                case "keys":
                    return executeKeys(redisTemplate, parts, startTime);
                case "exists":
                    return executeExists(redisTemplate, parts, startTime);
                case "expire":
                    return executeExpire(redisTemplate, parts, startTime);
                case "ttl":
                    return executeTtl(redisTemplate, parts, startTime);
                case "hget":
                    return executeHget(redisTemplate, parts, startTime);
                case "hset":
                    return executeHset(redisTemplate, parts, startTime);
                case "hgetall":
                    return executeHgetall(redisTemplate, parts, startTime);
                case "lpush":
                    return executeLpush(redisTemplate, parts, startTime);
                case "rpush":
                    return executeRpush(redisTemplate, parts, startTime);
                case "lrange":
                    return executeLrange(redisTemplate, parts, startTime);
                case "sadd":
                    return executeSadd(redisTemplate, parts, startTime);
                case "smembers":
                    return executeSmembers(redisTemplate, parts, startTime);
                case "info":
                    return executeInfo(redisTemplate, startTime);
                default:
                    return ExecuteResult.builder()
                            .success(false)
                            .message("不支持的命令: " + cmd)
                            .executeTime(System.currentTimeMillis() - startTime)
                            .errorMessage("请使用支持的命令")
                            .build();
            }
            
        } catch (Exception e) {
            log.error("执行 Redis 命令失败: {}", command, e);
            return ExecuteResult.builder()
                    .success(false)
                    .message("命令执行失败")
                    .executeTime(System.currentTimeMillis() - startTime)
                    .errorMessage(e.getMessage())
                    .errorStack(e.getStackTrace().toString())
                    .build();
        }
    }

    /**
     * 执行 GET 命令
     */
    private ExecuteResult executeGet(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 2) {
            return createErrorResult("GET 命令需要指定 key", startTime);
        }
        
        Object value = redisTemplate.opsForValue().get(parts[1]);
        List<Map<String, Object>> data = new ArrayList<>();
        Map<String, Object> result = new HashMap<>();
        result.put("key", parts[1]);
        result.put("value", value);
        data.add(result);
        
        return ExecuteResult.builder()
                .success(true)
                .message("GET 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .data(data)
                .build();
    }

    /**
     * 执行 SET 命令
     */
    private ExecuteResult executeSet(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 3) {
            return createErrorResult("SET 命令需要指定 key 和 value", startTime);
        }
        
        redisTemplate.opsForValue().set(parts[1], parts[2]);
        
        return ExecuteResult.builder()
                .success(true)
                .message("SET 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .affectedRows(1)
                .build();
    }

    /**
     * 执行 DEL 命令
     */
    private ExecuteResult executeDel(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 2) {
            return createErrorResult("DEL 命令需要指定 key", startTime);
        }
        
        Boolean result = redisTemplate.delete(parts[1]);
        
        return ExecuteResult.builder()
                .success(true)
                .message("DEL 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .affectedRows(result ? 1 : 0)
                .build();
    }

    /**
     * 执行 KEYS 命令
     */
    private ExecuteResult executeKeys(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 2) {
            return createErrorResult("KEYS 命令需要指定 pattern", startTime);
        }
        
        Set<String> keys = redisTemplate.keys(parts[1]);
        List<Map<String, Object>> data = new ArrayList<>();
        for (String key : keys) {
            Map<String, Object> item = new HashMap<>();
            item.put("key", key);
            data.add(item);
        }
        
        return ExecuteResult.builder()
                .success(true)
                .message("KEYS 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .data(data)
                .build();
    }

    /**
     * 执行 EXISTS 命令
     */
    private ExecuteResult executeExists(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 2) {
            return createErrorResult("EXISTS 命令需要指定 key", startTime);
        }
        
        Boolean exists = redisTemplate.hasKey(parts[1]);
        List<Map<String, Object>> data = new ArrayList<>();
        Map<String, Object> result = new HashMap<>();
        result.put("key", parts[1]);
        result.put("exists", exists);
        data.add(result);
        
        return ExecuteResult.builder()
                .success(true)
                .message("EXISTS 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .data(data)
                .build();
    }

    /**
     * 执行 EXPIRE 命令
     */
    private ExecuteResult executeExpire(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 3) {
            return createErrorResult("EXPIRE 命令需要指定 key 和 seconds", startTime);
        }
        
        Boolean result = redisTemplate.expire(parts[1], Long.parseLong(parts[2]), TimeUnit.SECONDS);
        
        return ExecuteResult.builder()
                .success(true)
                .message("EXPIRE 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .affectedRows(result ? 1 : 0)
                .build();
    }

    /**
     * 执行 TTL 命令
     */
    private ExecuteResult executeTtl(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 2) {
            return createErrorResult("TTL 命令需要指定 key", startTime);
        }
        
        Long ttl = redisTemplate.getExpire(parts[1], TimeUnit.SECONDS);
        List<Map<String, Object>> data = new ArrayList<>();
        Map<String, Object> result = new HashMap<>();
        result.put("key", parts[1]);
        result.put("ttl", ttl);
        data.add(result);
        
        return ExecuteResult.builder()
                .success(true)
                .message("TTL 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .data(data)
                .build();
    }

    /**
     * 执行 HGET 命令
     */
    private ExecuteResult executeHget(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 3) {
            return createErrorResult("HGET 命令需要指定 key 和 field", startTime);
        }
        
        Object value = redisTemplate.opsForHash().get(parts[1], parts[2]);
        List<Map<String, Object>> data = new ArrayList<>();
        Map<String, Object> result = new HashMap<>();
        result.put("key", parts[1]);
        result.put("field", parts[2]);
        result.put("value", value);
        data.add(result);
        
        return ExecuteResult.builder()
                .success(true)
                .message("HGET 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .data(data)
                .build();
    }

    /**
     * 执行 HSET 命令
     */
    private ExecuteResult executeHset(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 4) {
            return createErrorResult("HSET 命令需要指定 key、field 和 value", startTime);
        }
        
        redisTemplate.opsForHash().put(parts[1], parts[2], parts[3]);
        
        return ExecuteResult.builder()
                .success(true)
                .message("HSET 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .affectedRows(1)
                .build();
    }

    /**
     * 执行 HGETALL 命令
     */
    private ExecuteResult executeHgetall(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 2) {
            return createErrorResult("HGETALL 命令需要指定 key", startTime);
        }
        
        Map<Object, Object> hash = redisTemplate.opsForHash().entries(parts[1]);
        List<Map<String, Object>> data = new ArrayList<>();
        for (Map.Entry<Object, Object> entry : hash.entrySet()) {
            Map<String, Object> item = new HashMap<>();
            item.put("field", entry.getKey());
            item.put("value", entry.getValue());
            data.add(item);
        }
        
        return ExecuteResult.builder()
                .success(true)
                .message("HGETALL 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .data(data)
                .build();
    }

    /**
     * 执行 LPUSH 命令
     */
    private ExecuteResult executeLpush(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 3) {
            return createErrorResult("LPUSH 命令需要指定 key 和 value", startTime);
        }
        
        Long result = redisTemplate.opsForList().leftPush(parts[1], parts[2]);
        
        return ExecuteResult.builder()
                .success(true)
                .message("LPUSH 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .affectedRows(result.intValue())
                .build();
    }

    /**
     * 执行 RPUSH 命令
     */
    private ExecuteResult executeRpush(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 3) {
            return createErrorResult("RPUSH 命令需要指定 key 和 value", startTime);
        }
        
        Long result = redisTemplate.opsForList().rightPush(parts[1], parts[2]);
        
        return ExecuteResult.builder()
                .success(true)
                .message("RPUSH 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .affectedRows(result.intValue())
                .build();
    }

    /**
     * 执行 LRANGE 命令
     */
    private ExecuteResult executeLrange(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 4) {
            return createErrorResult("LRANGE 命令需要指定 key、start 和 stop", startTime);
        }
        
        List<Object> list = redisTemplate.opsForList().range(parts[1], 
                Long.parseLong(parts[2]), Long.parseLong(parts[3]));
        List<Map<String, Object>> data = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            Map<String, Object> item = new HashMap<>();
            item.put("index", i);
            item.put("value", list.get(i));
            data.add(item);
        }
        
        return ExecuteResult.builder()
                .success(true)
                .message("LRANGE 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .data(data)
                .build();
    }

    /**
     * 执行 SADD 命令
     */
    private ExecuteResult executeSadd(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 3) {
            return createErrorResult("SADD 命令需要指定 key 和 member", startTime);
        }
        
        Long result = redisTemplate.opsForSet().add(parts[1], parts[2]);
        
        return ExecuteResult.builder()
                .success(true)
                .message("SADD 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .affectedRows(result.intValue())
                .build();
    }

    /**
     * 执行 SMEMBERS 命令
     */
    private ExecuteResult executeSmembers(RedisTemplate<String, Object> redisTemplate, String[] parts, long startTime) {
        if (parts.length < 2) {
            return createErrorResult("SMEMBERS 命令需要指定 key", startTime);
        }
        
        Set<Object> members = redisTemplate.opsForSet().members(parts[1]);
        List<Map<String, Object>> data = new ArrayList<>();
        for (Object member : members) {
            Map<String, Object> item = new HashMap<>();
            item.put("member", member);
            data.add(item);
        }
        
        return ExecuteResult.builder()
                .success(true)
                .message("SMEMBERS 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .data(data)
                .build();
    }

    /**
     * 执行 INFO 命令
     */
    private ExecuteResult executeInfo(RedisTemplate<String, Object> redisTemplate, long startTime) {
        Properties info = redisTemplate.getConnectionFactory().getConnection().info();
        List<Map<String, Object>> data = new ArrayList<>();
        Map<String, Object> infoMap = new HashMap<>();
        for (String key : info.stringPropertyNames()) {
            infoMap.put(key, info.getProperty(key));
        }
        data.add(infoMap);
        
        return ExecuteResult.builder()
                .success(true)
                .message("INFO 命令执行成功")
                .executeTime(System.currentTimeMillis() - startTime)
                .data(data)
                .build();
    }

    /**
     * 创建错误结果
     */
    private ExecuteResult createErrorResult(String message, long startTime) {
        return ExecuteResult.builder()
                .success(false)
                .message(message)
                .executeTime(System.currentTimeMillis() - startTime)
                .errorMessage(message)
                .build();
    }
}
